Android音频子系统(四) 您所在的位置:网站首页 h5 耳机拔出 Android音频子系统(四)

Android音频子系统(四)

2024-01-09 19:40| 来源: 网络整理| 查看: 265

你好!这里是风筝的博客, 欢迎和我一起交流。

耳机上报主要有两种方式: 1.InputEvent 2.UEvent

输入子系统(InputEvent):可以上报按键事件也可以上报开关事件(EV_SW),事件类型包括headset、headPhone、lineOut。对于输入设备都需要指定能产生同步类事件EV_SYN. 对于按键事件,输入子系统还需要设置按键值的范围,但是对于开关类事件不需要设置。switch class子系统:通过uevent向用户空间发送数据,Android中有个线程专门监听这类事件。使用switch dev子系统时,名字必须要设置为"h2w",Android系统监听/sys/class/switch/h2w这个虚拟设备。

两种模式的切换可以使用配置项来完成,Android 系统默认是使用UEvent的方式。 不过一般厂商会在自己的xml文件里进行配置。 例如我这板子配置:

device/softwinner/ceres-spen/overlay/frameworks/base/core/res/res/values/config.xml:140: true

当config_useDevInputEventForAudioJack为false 则使用UEVent方式,为true则使用InputEvent方式,我这里使用的是InputEvent方式。

public WiredAccessoryManager(Context context, InputManagerService inputManager) { //这里涉及三个服务:电源子系统、输入输出子系统、音频子系统 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager"); mWakeLock.setReferenceCounted(false); mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); mInputManager = inputManager; mContext = context; mHdmiWakeLock=pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE, "HdmiWakeLock"); mHdmiWakeLock.setReferenceCounted(false); mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); mObserver = new WiredAccessoryObserver();//创建WiredAccessoryObserver对象 }

mUseDevInputEventForAudioJack即是获取xml文件中配置的config_useDevInputEventForAudioJack,这里为true。 接着创建WiredAccessoryObserver。 WiredAccessoryObserver是WiredAccessoryManager的内部类。

class WiredAccessoryObserver extends UEventObserver { private final List mUEventInfo; public WiredAccessoryObserver() { mUEventInfo = makeObservedUEventList(); } }

继续跟makeObservedUEventList

private List makeObservedUEventList() { List retVal = new ArrayList(); UEventInfo uei; // Monitor h2w if (!mUseDevInputEventForAudioJack) { uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC, BIT_LINEOUT); if (uei.checkSwitchExists()) { retVal.add(uei); } else { Slog.w(TAG, "This kernel does not have wired headset support"); } } // Monitor USB uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL, 0); if (uei.checkSwitchExists()) { retVal.add(uei); } else { Slog.w(TAG, "This kernel does not have usb audio support"); } // Monitor HDMI boolean isBOX = "box".equals(SystemProperties.get("ro.target.product", "box")); if (!isBOX) { uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0, 0); if (uei.checkSwitchExists()) { retVal.add(uei); } else { uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0, 0); if (uei.checkSwitchExists()) { retVal.add(uei); } else { Slog.w(TAG, "This kernel does not have HDMI audio support"); } } } // Monitor DP uei = new UEventInfo(NAME_DP, BIT_HDMI_AUDIO, 0, 0); if (uei.checkSwitchExists()) { retVal.add(uei); } else { Slog.w(TAG, "This kernel does not have dp audio support"); } return retVal; }

通过注释可知,里面主要监听各个节点,那么它是什么时候启动监听的呢?

private void startOtherServices() { // ... traceBeginAndSlog("StartWiredAccessoryManager"); try { // Listen for wired headset changes inputManager.setWiredAccessoryCallbacks( new WiredAccessoryManager(context, inputManager));//设置WiredAccessoryCallbacks } catch (Throwable e) { reportWtf("starting WiredAccessoryManager", e); } // ... final InputManagerService inputManagerF = inputManager; // ... try { // TODO(BT) Pass parameter to input manager if (inputManagerF != null) inputManagerF.systemRunning();//调用systemRunning,这里先记下,下面会看到用途 } catch (Throwable e) { reportWtf("Notifying InputManagerService running", e); } }

在startOtherServices里面,setWiredAccessoryCallbacks的入参就是创建WiredAccessoryManager!

@InputManagerService.java public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) { mWiredAccessoryCallbacks = callbacks; }

里面主要是赋值操作,就类似于mWiredAccessoryCallbacks = new WiredAccessoryManager。

全局搜下mWiredAccessoryCallbacks在哪里被调用了,还真找到一处:

// Native callback. private void notifySwitch(long whenNanos, int switchValues, int switchMask) { if (DEBUG) { Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues) + ", mask=" + Integer.toHexString(switchMask)); } if ((switchMask & SW_LID_BIT) != 0) { final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0); mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); } if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) { final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0); mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered); } if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) { mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues, switchMask);//这里回调notifyWiredAccessoryChanged方法 } if ((switchMask & SW_TABLET_MODE_BIT) != 0) { SomeArgs args = SomeArgs.obtain(); args.argi1 = (int) (whenNanos & 0xFFFFFFFF); args.argi2 = (int) (whenNanos >> 32); args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0); mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED, args).sendToTarget(); } }

之前我们提及,xml解析出来mUseDevInputEventForAudioJack为true,这里就会进入mWiredAccessoryCallbacks.notifyWiredAccessoryChanged

// FROM: kernal --> InputManagerService --> WiredAccessoryManager.java ---> ,,, @Override public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) { if (LOG) Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos + " bits=" + switchCodeToString(switchValues, switchMask) + " mask=" + Integer.toHexString(switchMask)); //耳机种类 synchronized (mLock) { int headset; mSwitchValues = (mSwitchValues & ~switchMask) | switchValues; switch (mSwitchValues & (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT)) { case 0: headset = 0; break; case SW_HEADPHONE_INSERT_BIT: headset = BIT_HEADSET_NO_MIC; break; case SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT: headset = BIT_HEADSET; break; case SW_MICROPHONE_INSERT_BIT: headset = BIT_HEADSET; break; default: headset = 0; break; } updateLocked(NAME_H2W, (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC)) | headset); } } /** * Compare the existing headset state with the new state and pass along accordingly. Note * that this only supports a single headset at a time. Inserting both a usb and jacked headset * results in support for the last one plugged in. Similarly, unplugging either is seen as * unplugging all. * * @param newName One of the NAME_xxx variables defined above. * @param newState 0 or one of the BIT_xxx variables defined above. */ private void updateLocked(String newName, int newState) { // Retain only relevant bits int headsetState = newState & SUPPORTED_HEADSETS; int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG; int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL; int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC); boolean h2wStateChange = true; boolean usbStateChange = true; //打印相关信息,耳机设备名称,最新状态,更新前状态 //这里可以查看log信息 if (LOG) Slog.v(TAG, "newName=" + newName + " newState=" + newState + " headsetState=" + headsetState + " prev headsetState=" + mHeadsetState); if (mHeadsetState == headsetState) { Log.e(TAG, "No state change."); return; } // reject all suspect transitions: only accept state changes from: // - a: 0 headset to 1 headset // - b: 1 headset to 0 headset if (h2w_headset == (BIT_HEADSET | BIT_HEADSET_NO_MIC)) { Log.e(TAG, "Invalid combination, unsetting h2w flag"); h2wStateChange = false; } // - c: 0 usb headset to 1 usb headset // - d: 1 usb headset to 0 usb headset if (usb_headset_anlg == BIT_USB_HEADSET_ANLG && usb_headset_dgtl == BIT_USB_HEADSET_DGTL) { Log.e(TAG, "Invalid combination, unsetting usb flag"); usbStateChange = false; } if (!h2wStateChange && !usbStateChange) { Log.e(TAG, "invalid transition, returning ..."); return; } mWakeLock.acquire(); //发送消息处理,告知当前状态改变,继续做更新处理。 Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState, mHeadsetState, newName); mHandler.sendMessage(msg); //刷新保存当前最新状态 mHeadsetState = headsetState; }

最后会通过Handler发送消息。

private final Handler mHandler = new Handler(Looper.myLooper(), null, true) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_NEW_DEVICE_STATE: //分别对应:new_headSet_status,old_headSet_status,newName setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); mWakeLock.release(); break; case MSG_SYSTEM_READY: onSystemReady(); mWakeLock.release(); break; } } }; private void setDevicesState( int headsetState, int prevHeadsetState, String headsetName) { synchronized (mLock) { int allHeadsets = SUPPORTED_HEADSETS; for (int curHeadset = 1; allHeadsets != 0; curHeadset setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName);//继续跟踪 allHeadsets &= ~curHeadset; } } } } private void setDeviceStateLocked(int headset, int headsetState, int prevHeadsetState, String headsetName) { if ((headsetState & headset) != (prevHeadsetState & headset)) {//状态改变了 int outDevice = 0; int inDevice = 0; int state; //当耳机插入和拔出,上报的event中,分别是1和0因此这里的state应该是决定当前是插入还是拔出耳机 if ((headsetState & headset) != 0) { state = 1;//插入耳机 } else { state = 0;//拔出耳机 } if (headset == BIT_HEADSET) {//这里就是根据耳机的类型,设置相应的音频输入和输出设备了 outDevice = AudioManager.DEVICE_OUT_WIRED_HEADSET; inDevice = AudioManager.DEVICE_IN_WIRED_HEADSET; } else if (headset == BIT_HEADSET_NO_MIC){ outDevice = AudioManager.DEVICE_OUT_WIRED_HEADPHONE; } else if (headset == BIT_LINEOUT){ outDevice = AudioManager.DEVICE_OUT_LINE; } else if (headset == BIT_USB_HEADSET_ANLG) { outDevice = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET; } else if (headset == BIT_USB_HEADSET_DGTL) { outDevice = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET; } else if (headset == BIT_HDMI_AUDIO) { outDevice = AudioManager.DEVICE_OUT_HDMI; } else { Slog.e(TAG, "setDeviceState() invalid headset type: "+headset); return; } if (LOG) { Slog.v(TAG, "headsetName: " + headsetName + (state == 1 ? " connected" : " disconnected")); } if (outDevice != 0) { mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);//连接输出设备 } if (inDevice != 0) { mAudioManager.setWiredDeviceConnectionState(inDevice, state, "", headsetName);//连接输入设备 } //...... } }

看下这里是如何连接设备的:

@AudioManager.java public void setWiredDeviceConnectionState(int type, int state, String address, String name) { IAudioService service = getService(); try { service.setWiredDeviceConnectionState(type, state, address, name, mApplicationContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AudioService.java public void setWiredDeviceConnectionState(int type, int state, String address, String name, String caller) { synchronized (mConnectedDevices) { if (DEBUG_DEVICES) { Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:" + address + ")"); } int delay = checkSendBecomingNoisyIntent(type, state); queueMsgUnderWakeLock(mAudioHandler, MSG_SET_WIRED_DEVICE_CONNECTION_STATE, 0, 0, new WiredDeviceConnectionState(type, state, address, name, caller),//最后会调用到handleMessage处理 delay); } }

这里的queueMsgUnderWakeLock代码实现如下:

private void queueMsgUnderWakeLock(Handler handler, int msg, int arg1, int arg2, Object obj, int delay) { final long ident = Binder.clearCallingIdentity(); // Always acquire the wake lock as AudioService because it is released by the // message handler. mAudioEventWakeLock.acquire(); Binder.restoreCallingIdentity(ident); sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay); }

handler对于MSG_SET_WIRED_DEVICE_CONNECTION_STATE消息进行处理,代码如下:

@Override public void handleMessage(Message msg) { // ... case MSG_SET_WIRED_DEVICE_CONNECTION_STATE: { WiredDeviceConnectionState connectState = (WiredDeviceConnectionState)msg.obj; onSetWiredDeviceConnectionState(connectState.mType, connectState.mState, connectState.mAddress, connectState.mName, connectState.mCaller); mAudioEventWakeLock.release(); } break; break; // ... } //called from AudioHandler::handleMessage(Message msg) private void onSetWiredDeviceConnectionState(int device, int state, String address, String deviceName, String caller) { if (DEBUG_DEVICES) { Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device) + " state:" + Integer.toHexString(state) + " address:" + address + " deviceName:" + deviceName + " caller: " + caller + ");"); } synchronized (mConnectedDevices) { if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) || (device == AudioSystem.DEVICE_OUT_LINE))) { setBluetoothA2dpOnInt(true); } boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) || (((device & AudioSystem.DEVICE_BIT_IN) != 0) && ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0)); if (!handleDeviceConnection(state == 1, device, address, deviceName)) {//关键点1:设备切换入口 // change of connection state failed, bailout return; } if (state != 0) {//连接状态 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) || (device == AudioSystem.DEVICE_OUT_LINE)) { setBluetoothA2dpOnInt(false); } if ((device & mSafeMediaVolumeDevices) != 0) { sendMsg(mAudioHandler, MSG_CHECK_MUSIC_ACTIVE, SENDMSG_REPLACE, 0, 0, caller, MUSIC_ACTIVE_POLL_PERIOD_MS); } // Television devices without CEC service apply software volume on HDMI output if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) { mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI; checkAllFixedVolumeDevices(); if (mHdmiManager != null) { synchronized (mHdmiManager) { if (mHdmiPlaybackClient != null) { mHdmiCecSink = false; mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback); } } } } } else { if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) { if (mHdmiManager != null) { synchronized (mHdmiManager) { mHdmiCecSink = false; } } } } if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) { //可以看到耳机插入,这里发送广播给上层app去接收。systemui会接收该广播,显示耳机插入图标。 //当然可以继续往下跟。直到sendbroadcast。 sendDeviceConnectionIntent(device, state, address, deviceName);//关键点2:通过AMS上报intent } } }

先看handleDeviceConnection,这里主要是对于插入耳机之后要做设备切换:

private boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) { if (DEBUG_DEVICES) { Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device) + " address:" + address + " name:" + deviceName + ")"); } synchronized (mConnectedDevices) { String deviceKey = makeDeviceListKey(device, address); if (DEBUG_DEVICES) { Slog.i(TAG, "deviceKey:" + deviceKey); } DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey); boolean isConnected = deviceSpec != null; if (DEBUG_DEVICES) { Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected); } boolean isSpdifOrHdmi = ((device == AudioSystem.DEVICE_OUT_SPDIF) || (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL)); if (isSpdifOrHdmi) {//我们既不是spdif也不是hdmi,先不用管 if (!connect) { AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName); mConnectedDevices.remove(deviceKey); return true; } else { AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName); mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address)); return true; } } if (connect && !isConnected) {//连接处理 final int res = AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName); if (res != AudioSystem.AUDIO_STATUS_OK) { Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) + " due to command error " + res ); return false; } mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address)); return true; } else if (!connect && isConnected) {//断开连接处理 AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName); // always remove even if disconnection failed mConnectedDevices.remove(deviceKey); return true; } } return false; }

可以看出,不管是插入连接还是拔出点开,都是进入AudioSystem.setDeviceConnectionState,仅仅是参数不同而已!

@AudioSystem.java public static native int setDeviceConnectionState(int device, int state, String device_address, String device_name);

这里setDeviceConnectionState为native方法,所以去看它jni对应的实现,它的JNI映射关系为:

{"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState}

继续分析android_media_AudioSystem_setDeviceConnectionState的实现:

static jint android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name) { const char *c_address = env->GetStringUTFChars(device_address, NULL); const char *c_name = env->GetStringUTFChars(device_name, NULL); int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast (device), static_cast (state), c_address, c_name)); env->ReleaseStringUTFChars(device_address, c_address); env->ReleaseStringUTFChars(device_name, c_name); return (jint) status; }

继续往下跟AudioSystem::setDeviceConnectionState

status_t AudioSystem::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address, const char *device_name) { const sp& aps = AudioSystem::get_audio_policy_service(); const char *address = ""; const char *name = ""; if (aps == 0) return PERMISSION_DENIED; if (device_address != NULL) { address = device_address; } if (device_name != NULL) { name = device_name; } return aps->setDeviceConnectionState(device, state, address, name); }

嗯,这里终于看到熟悉的aps(AudioPolicyService)了,泪目~ 先获取对应的AudioPolicyService,接着调用setDeviceConnectionState

status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address, const char *device_name) { if (mAudioPolicyManager == NULL) { return NO_INIT; } if (!settingsAllowed()) { return PERMISSION_DENIED; } if (!audio_is_output_device(device) && !audio_is_input_device(device)) { return BAD_VALUE; } if (state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE && state != AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) { return BAD_VALUE; } ALOGV("setDeviceConnectionState()"); Mutex::Autolock _l(mLock); return mAudioPolicyManager->setDeviceConnectionState(device, state, device_address, device_name); }

继续调用AudioPolicyManager对应setDeviceConnectionState

status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address, const char *device_name) { return setDeviceConnectionStateInt(device, state, device_address, device_name); } status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address, const char *device_name) { ALOGV("setDeviceConnectionStateInt() device: 0x%X, state %d, address %s name %s", - device, state, device_address, device_name); // connect/disconnect only 1 device at a time if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE; sp devDesc = mHwModules.getDeviceDescriptor(device, device_address, device_name);//获取设备描述符 // 处理输出设备 if (audio_is_output_device(device)) { SortedVector outputs; ssize_t index = mAvailableOutputDevices.indexOf(devDesc); // 在通过checkOutputsForDevice()打开或关闭任何输出之前,请保存打开的输出描述符的副本。 //checkOutputForAllStrategies()将需要它 mPreviousOutputs = mOutputs; switch (state) { // handle output device connection case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: { if (index >= 0) { ALOGW("setDeviceConnectionState() device already connected: %x", device); return INVALID_OPERATION; } ALOGV("setDeviceConnectionState() connecting device %x", device); // register new device as available index = mAvailableOutputDevices.add(devDesc); if (index >= 0) { sp module = mHwModules.getModuleForDevice(device); if (module == 0) { ALOGD("setDeviceConnectionState() could not find HW module for device %08x", device); mAvailableOutputDevices.remove(devDesc); return INVALID_OPERATION; } mAvailableOutputDevices[index]->attach(module); } else { return NO_MEMORY; } if (checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress) != NO_ERROR) { mAvailableOutputDevices.remove(devDesc); return INVALID_OPERATION; } // Propagate device availability to Engine mEngine->setDeviceConnectionState(devDesc, state); // outputs should never be empty here ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():" "checkOutputsForDevice() returned no outputs but status OK"); ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs", outputs.size()); // Send connect to HALs AudioParameter param = AudioParameter(devDesc->mAddress); param.addInt(String8(AUDIO_PARAMETER_DEVICE_CONNECT), device); mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString()); } break; // handle output device disconnection case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: { if (index for (size_t i = 0; i closeOutput(outputs[i]); } } // check again after closing A2DP output to reset mA2dpSuspended if needed checkA2dpSuspend(); } updateDevicesAndOutputs(); if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); updateCallRouting(newDevice); } for (size_t i = 0; i audio_devices_t newDevice = getNewOutputDevice(desc, true /*fromCache*/); // do not force device change on duplicated output because if device is 0, it will // also force a device 0 for the two outputs it is duplicated to which may override // a valid device selection on those outputs. bool force = !desc->isDuplicated() && (!device_distinguishes_on_address(device) // always force when disconnecting (a non-duplicated device) || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)); setOutputDevice(desc, newDevice, force, 0); } } if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) { cleanUpForDevice(devDesc); } mpClientInterface->onAudioPortListUpdate(); return NO_ERROR; } // end if is output device // handle input devices if (audio_is_input_device(device)) { SortedVector inputs; ssize_t index = mAvailableInputDevices.indexOf(devDesc); switch (state) { // handle input device connection case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: { if (index >= 0) { ALOGW("setDeviceConnectionState() device already connected: %d", device); return INVALID_OPERATION; } sp module = mHwModules.getModuleForDevice(device); if (module == NULL) { ALOGW("setDeviceConnectionState(): could not find HW module for device %08x", device); return INVALID_OPERATION; } if (checkInputsForDevice(devDesc, state, inputs, devDesc->mAddress) != NO_ERROR) { return INVALID_OPERATION; } index = mAvailableInputDevices.add(devDesc); if (index >= 0) { mAvailableInputDevices[index]->attach(module); } else { return NO_MEMORY; } // Set connect to HALs AudioParameter param = AudioParameter(devDesc->mAddress); param.addInt(String8(AUDIO_PARAMETER_DEVICE_CONNECT), device); mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString()); // Propagate device availability to Engine mEngine->setDeviceConnectionState(devDesc, state); } break; // handle input device disconnection case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: { if (index audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); updateCallRouting(newDevice); } if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) { cleanUpForDevice(devDesc); } mpClientInterface->onAudioPortListUpdate(); return NO_ERROR; } // end if is input device ALOGW("setDeviceConnectionState() invalid device: %x", device); return BAD_VALUE; }

这玩意还真有点多,避免累诉过多,见注释,这里以输出设备为例:

同一时间,只能连接输入或者输出设备;获取设备描述符,注册新设备到mAvailableOutputDevices,绑定其HwModules;通过device获取module。

这个module很重要,它对应了不同的hal层库,比如我的系统当前有三个hal层库,分别是primary,usb和a2dp(即蓝牙,支持立体声播放的),既然找到了module,那么必然要尝试按照这个device去hal层打开输出流,看是否OK,不同的module对应的device在哪里看,也就是audiopolicyservice启机时候加载的audio_policy.conf文件,如果在实际问题处理中,你认为的device没有进入到对应的hal层时,请注意在audio_policy.conf中对应的module下面去添加device。

checkOutputsForDevice 检查设备支持profile,hal层会去打开这个output,更新output参数;发送连接到HAL层;checkA2dpSuspend 检查是否支持a2dp;checkOutputForAllStrategies检查所有音频 strategy,并将不一致outputs,对应track置为无效;closeOutput 设备断开连接,执行checkOutputForAllStrategies()后必须关闭输出。updateDevicesAndOutputs 更新devices 和outputs;setOutputDevice 设置输出设备;

插入耳机,最重要的当然是切换设备了,所以我们重点看下checkOutputsForDevice函数:

status_t AudioPolicyManager::checkOutputsForDevice(const sp devDesc, audio_policy_dev_state_t state, SortedVector& outputs, const String8 address) { audio_devices_t device = devDesc->type(); sp desc; if (audio_device_is_digital(device)) { // erase all current sample rates, formats and channel masks devDesc->clearAudioProfiles(); } if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) { // first list already open outputs that can be routed to this device //先列举出已经打开的能routed到这个device的outputs for (size_t i = 0; i if (!device_distinguishes_on_address(device)) { ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i)); outputs.add(mOutputs.keyAt(i)); } else { ALOGV(" checking address match due to device 0x%x", device); findIoHandlesByAddress(desc, device, address, outputs); } } } // then look for output profiles that can be routed to this device //然后查找能routed到此device的output profiles SortedVector profiles; for (size_t i = 0; i continue; } for (size_t j = 0; j mOutputProfiles.size(); j++) { sp profile = mHwModules[i]->mOutputProfiles[j]; if (profile->supportDevice(device)) { if (!device_distinguishes_on_address(device) || profile->supportDeviceAddress(address)) { profiles.add(profile); ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i); } } } } //...... // open outputs for matching profiles if needed. Direct outputs are also opened to // query for dynamic parameters and will be closed later by setDeviceConnectionState() //如果需要的话给匹配的profiles打开outputs(已经打开过就啥也不干) for (ssize_t profile_index = 0; profile_index desc = mOutputs.valueFor(outputs.itemAt(j)); if (!desc->isDuplicated() && desc->mProfile == profile) { // matching profile: save the sample rates, format and channel masks supported // by the profile in our device descriptor if (audio_device_is_digital(device)) { devDesc->importAudioPort(profile); } break; } } if (j != outputs.size()) { continue; } ALOGV("opening output for device %08x with params %s profile %p", device, address.string(), profile.get()); desc = new SwAudioOutputDescriptor(profile, mpClientInterface); desc->mDevice = device; audio_config_t config = AUDIO_CONFIG_INITIALIZER; config.sample_rate = desc->mSamplingRate; config.channel_mask = desc->mChannelMask; config.format = desc->mFormat; config.offload_info.sample_rate = desc->mSamplingRate; config.offload_info.channel_mask = desc->mChannelMask; config.offload_info.format = desc->mFormat; audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; //打开输出设备 status_t status = mpClientInterface->openOutput(profile->getModuleHandle(), &output, &config, &desc->mDevice, address, &desc->mLatency, desc->mFlags); if (status == NO_ERROR) { desc->mSamplingRate = config.sample_rate; desc->mChannelMask = config.channel_mask; desc->mFormat = config.format; // Here is where the out_set_parameters() for card & device gets called if (!address.isEmpty()) { char *param = audio_device_address_to_parameter(device, address); mpClientInterface->setParameters(output, String8(param)); free(param); } updateAudioProfiles(device, output, profile->getAudioProfiles()); if (!profile->hasValidAudioProfile()) { ALOGW("checkOutputsForDevice() missing param"); mpClientInterface->closeOutput(output); output = AUDIO_IO_HANDLE_NONE; } else if (profile->hasDynamicAudioProfile()) { mpClientInterface->closeOutput(output); output = AUDIO_IO_HANDLE_NONE; profile->pickAudioProfile(config.sample_rate, config.channel_mask, config.format); config.offload_info.sample_rate = config.sample_rate; config.offload_info.channel_mask = config.channel_mask; config.offload_info.format = config.format; status = mpClientInterface->openOutput(profile->getModuleHandle(), &output, &config, &desc->mDevice, address, &desc->mLatency, desc->mFlags); if (status == NO_ERROR) { desc->mSamplingRate = config.sample_rate; desc->mChannelMask = config.channel_mask; desc->mFormat = config.format; } else { output = AUDIO_IO_HANDLE_NONE; } } if (output != AUDIO_IO_HANDLE_NONE) { addOutput(output, desc); if (device_distinguishes_on_address(device) && address != "0") { sp policyMix; if (mPolicyMixes.getAudioPolicyMix(address, policyMix) != NO_ERROR) { ALOGE("checkOutputsForDevice() cannot find policy for address %s", address.string()); } policyMix->setOutput(desc); desc->mPolicyMix = policyMix->getMix(); } else if (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) && hasPrimaryOutput()) { // no duplicated output for direct outputs and // outputs used by dynamic policy mixes audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE; // set initial stream volume for device applyStreamVolumes(desc, device, 0, true); //TODO: configure audio effect output stage here // open a duplicating output thread for the new output and the primary output duplicatedOutput = mpClientInterface->openDuplicateOutput(output, mPrimaryOutput->mIoHandle); if (duplicatedOutput != AUDIO_IO_HANDLE_NONE) { // add duplicated output descriptor sp dupOutputDesc = new SwAudioOutputDescriptor(NULL, mpClientInterface); dupOutputDesc->mOutput1 = mPrimaryOutput; dupOutputDesc->mOutput2 = desc; dupOutputDesc->mSamplingRate = desc->mSamplingRate; dupOutputDesc->mFormat = desc->mFormat; dupOutputDesc->mChannelMask = desc->mChannelMask; dupOutputDesc->mLatency = desc->mLatency; addOutput(duplicatedOutput, dupOutputDesc); applyStreamVolumes(dupOutputDesc, device, 0, true); } else { ALOGW("checkOutputsForDevice() could not open dup output for %d and %d", mPrimaryOutput->mIoHandle, output); mpClientInterface->closeOutput(output); removeOutput(output); nextAudioPortGeneration(); output = AUDIO_IO_HANDLE_NONE; } } } } else { output = AUDIO_IO_HANDLE_NONE; } if (output == AUDIO_IO_HANDLE_NONE) { ALOGW("checkOutputsForDevice() could not open output for device %x", device); profiles.removeAt(profile_index); profile_index--; } else { outputs.add(output); // Load digital format info only for digital devices if (audio_device_is_digital(device)) { devDesc->importAudioPort(profile); } if (device_distinguishes_on_address(device)) { ALOGV("checkOutputsForDevice(): setOutputDevice(dev=0x%x, addr=%s)", device, address.string()); setOutputDevice(desc, device, true/*force*/, 0/*delay*/, NULL/*patch handle*/, address.string()); } ALOGV("checkOutputsForDevice(): adding output %d", output); } } if (profiles.isEmpty()) { ALOGW("checkOutputsForDevice(): No output available for device %04x", device); return BAD_VALUE; } } else { // Disconnect // check if one opened output is not needed any more after disconnecting one device for (size_t i = 0; i // exact match on device if (device_distinguishes_on_address(device) && (desc->supportedDevices() == device)) { findIoHandlesByAddress(desc, device, address, outputs); } else if (!(desc->supportedDevices() & mAvailableOutputDevices.types())) { ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i)); outputs.add(mOutputs.keyAt(i)); } } } // Clear any profiles associated with the disconnected device. for (size_t i = 0; i continue; } for (size_t j = 0; j mOutputProfiles.size(); j++) { sp profile = mHwModules[i]->mOutputProfiles[j]; if (profile->supportDevice(device)) { ALOGV("checkOutputsForDevice(): " "clearing direct output profile %zu on module %zu", j, i); profile->clearAudioProfiles(); } } } } return NO_ERROR; }

切换设备对于audio来说,是很重要的一个知识点,这里我也没有吃太透,后续等我理解了再专门来写吧~ 不过可以简单看出,里面会调用到mpClientInterface->openOutput,这里最后的openOutput流程,就是打开输出了,可以参考之前的文章:Android音频子系统(一)------openOutput打开流程

最后看下图标显示吧~

@frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java private void updateHeadsetPlug(Intent intent) { boolean connected = intent.getIntExtra("state", 0) != 0; boolean hasMic = intent.getIntExtra("microphone", 0) != 0; Log.w(TAG, "updateHeadsetPlug connected: " + connected + " hasMic: " + hasMic); if (connected) { String contentDescription = mContext.getString(hasMic ? R.string.accessibility_status_bar_headset : R.string.accessibility_status_bar_headphones); mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.stat_sys_headset_mic : R.drawable.stat_sys_headset, contentDescription); mIconController.setIconVisibility(mSlotHeadset, true); } else { mIconController.setIconVisibility(mSlotHeadset, false); } }

updateHeadsetPlug里面获取耳机挂载的广播,判断是headset(带麦耳机)还是headphones,在状态栏显示对应的图标! headset对应R.drawable.stat_sys_headset_mic;headphones对应R.drawable.stat_sys_headset。 我的这个项目里面,耳机图标路径在:frameworks/base/packages/SystemUI/res/drawable/stat_sys_headset_mic.xml (drawable目录)



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有